﻿using Dimeng.ArdisPostProcessor.HomagLC4.Ardis;
using ReadR41;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dimeng.ArdisPostProcessor.HomagLC4Adsn.Ardis
{
    public class BlockOptimizer
    {
        public static void Optimize(R41Data data)
        {
            foreach (var pattern in data.Patterns)
            {
                int counter = data.Cuts.Max(it => it.CutNo) + 1;

                var cuts = data.Cuts
                               .Where(c => c.CutPatternNo == pattern.PatternNumber
                                           && c.CutLevel == 1)
                               //.OrderBy(c => c.CutNo)
                               .ToList();

                double Length = pattern.PatternL;
                double Width = pattern.PatternW;

                optimizeCuts(data, cuts, Length, Width, pattern, ref counter);
            }
        }

        private static void optimizeCuts(R41Data data, List<Cut> cuts, double length, double width, Pattern pattern, ref int counter)
        {
            ////如果level=1就开始搜索的话，会大大破坏优化结果
            //if (cuts[0].CutLevel == 1)
            //{
            //    if (cuts[0].CutD == 'H')
            //    {
            //        length = cuts[0].CutW;
            //    }
            //    else
            //    {
            //        width = cuts[0].CutW;
            //    }
            //    var children = data.Cuts.Where(it => it.CutParentNo == cuts[0].CutNo).ToList();
            //    optimizeCuts(data, children, length, width, pattern, ref counter);
            //    return;
            //}

            //做一次排序
            //让ardis的工程设定来修改
            //cuts = cuts.OrderByDescending(it => getCutLength(data, it, it.CutD == 'H' ? width : length)).ToList();

            double condition = 50;//超过50mm就不优化

            List<Cut> tempcuts = new List<Cut>();//
            double maxCutLength = 0;

            for (int i = 0; i < cuts.Count; i++)
            {
                var cut = cuts[i];

                if (cut.CutPartNo > 0)
                {
                    //如果这个切割直接出板件,直接跳开，继续下面的cut
                    maxCutLength = 0;
                    tempcuts.Clear();
                    continue;
                }

                //如果当前的cut的子cut并不都是part，就跳过这个cut的计算
                //或者都是part，但是没有余料剩下，导致顶格
                double cutLength = getCutLength(data, cut, cut.CutD == 'H' ? width : length);
                if (!data.Cuts.Where(it => it.CutParentNo == cut.CutNo).All(it => it.CutPartNo > 0)//todo:根据每个strip的使用率来判断是否合并到计算中比较好
                    || (cutLength == (cuts[0].CutD == 'H' ? width : length)))
                {
                    if (
                        (tempcuts.Count > 1 ||
                            (tempcuts.Count == 1 && tempcuts[0].CutQty > 1))
                        )
                    {
                        //把之前的结束了，生成一个block
                        if (maxCutLength == 0)
                            throw new Exception("max cut length could not be zero!");

                        resetCuts(data, tempcuts, maxCutLength, cut.CutD == 'H' ? width : length, ref counter);
                        //清空
                        maxCutLength = 0;
                        tempcuts.Clear();
                    }
                    else
                    {
                        //清空
                        maxCutLength = 0;
                        tempcuts.Clear();

                        //todo：把子cut继续优化
                        if (cut.CutD == 'H')
                        {
                            length = cut.CutW;
                        }
                        else
                        {
                            width = cut.CutW;
                        }
                        var children2 = data.Cuts.Where(it => it.CutParentNo == cut.CutNo).ToList();
                        optimizeCuts(data, children2, length, width, pattern, ref counter);
                    }
                    continue;
                }

                //所有的子cut都是part，才加入到合并计算中

                if (tempcuts.Count == 0)//上一个是否是可标记的,基本只针对第一次判断
                {
                    //上一个是不可用的，则将当前置为可用
                    maxCutLength = cutLength;
                    tempcuts.Add(cut);
                }
                else //上一个是可用的
                {
                    //判断长度差
                    if (maxCutLength - cutLength <= condition && maxCutLength - cutLength > 0)//长度差足够，添加到tempcuts里
                    { tempcuts.Add(cut); }
                    else//长度差不够
                    {
                        //结束掉上一个
                        if (tempcuts.Count > 1 || (tempcuts.Count == 1 && tempcuts[0].CutQty > 1))
                        {
                            //把之前的tempcuts处理掉
                            resetCuts(data, tempcuts, maxCutLength, cuts[0].CutD == 'H' ? width : length, ref counter);
                        }

                        tempcuts.Clear();

                        //重启一个新的
                        maxCutLength = cutLength;
                        tempcuts.Add(cut);
                    }
                }

                //最后一个的时候
                if (i == (cuts.Count - 1) &&
                    (tempcuts.Count > 1 ||
                        (tempcuts.Count == 1 && tempcuts[0].CutQty > 1)))
                {
                    resetCuts(data, tempcuts, maxCutLength, cuts[0].CutD == 'H' ? width : length, ref counter);
                }
            }
        }

        private static double getCutLength(R41Data data, Cut cut, double parentCutLength)
        {
            if (cut.CutPartNo == 0)
            {
                var children = data.Cuts.Where(it => it.CutParentNo == cut.CutNo).ToList();
                return -cut.Kerf + children.Sum(it => (it.CutW + it.Kerf) * it.CutQty);
            }
            else//part
            {
                return parentCutLength;
            }
        }

        private static void resetCuts(R41Data data, List<Cut> tempcuts, double maxCutLength, double cutWidth, ref int counter)
        {
            if (tempcuts.Count == 0)
            {
                throw new Exception("temp cuts must have children!");
            }

            var pattern = data.Patterns.Find(it => it.PatternNumber == tempcuts[0].CutPatternNo);
            var material = data.Materials.Find(it => pattern.PatternMaterial.ToUpper() == it.MaterialName.ToUpper());

            //转换成一张板件
            Part part = new Part();
            part.PartNo = data.Parts.Count + 1;
            part.PartRef = "block" + part.PartNo.ToString();
            part.PartQty = pattern.PatternQty;//todo:pattern qty
            part.PartL = tempcuts[0].CutD == 'H' ? maxCutLength : cutWidth;
            part.PartW = tempcuts[0].CutD == 'H' ? cutWidth : maxCutLength;
            part.PartMatNo = material.MaterialNo;//todo:mat no ????
            part.PartD = 1;
            data.Parts.Add(part);

            //创建一个新cut，切断所有的cut
            Cut cut = new Cut();
            cut.CutNo = counter;
            counter++;
            cut.CutLevel = tempcuts[0].CutLevel;
            cut.CutD = tempcuts[0].CutD;
            cut.CutParentNo = tempcuts[0].CutParentNo;
            cut.CutPartNo = 0;//strip
            cut.CutPatternNo = tempcuts[0].CutPatternNo;
            cut.CutQty = 1;//一刀完事
            cut.CutType = tempcuts[0].CutType;
            cut.CutW = tempcuts.Sum(it => (it.CutW + it.Kerf) * it.CutQty) - tempcuts[0].Kerf;
            cut.Kerf = tempcuts[0].Kerf;
            data.Cuts.Add(cut);

            //创建一个新cut，切断所有的cut
            Cut cut2 = new Cut();
            cut2.CutNo = counter;
            counter++;
            cut2.CutLevel = tempcuts[0].CutLevel + 1;
            cut2.CutD = tempcuts[0].CutD == 'H' ? 'V' : 'H';
            cut2.CutParentNo = cut.CutNo;
            cut2.CutPartNo = part.PartNo;//part
            cut2.CutPatternNo = tempcuts[0].CutPatternNo;
            cut2.CutQty = 1;//一刀完事
            cut2.CutType = tempcuts[0].CutType;
            cut2.CutW = maxCutLength;
            cut2.Kerf = tempcuts[0].Kerf;
            data.Cuts.Add(cut2);

            tempcuts.ForEach(it =>
            {
                it.CutLevel = 1;
                it.CutParentNo = 0;
                it.CutPatternNo = part.PartNo;//指向了板件号码

                if (it.CutPartNo == 0)
                {
                    var children = data.Cuts.Where(c => c.CutParentNo == it.CutNo).ToList();
                    //用递归的方式，把所有的子cut，也从cuts中去掉，存入blockcuts
                    addCutToBlockCutList(data, children, 2, part.PartNo);
                }
                data.BlockCuts.Add(it);
                data.Cuts.Remove(it);
            });//
        }

        private static void addCutToBlockCutList(R41Data data, List<Cut> children, int level, int patternNo)
        {
            foreach (var c in children)
            {
                c.CutLevel = level;
                c.CutPatternNo = patternNo;

                if (c.CutPartNo == 0)
                {
                    var children2 = data.Cuts.Where(x => x.CutParentNo == c.CutNo).ToList();
                    //用递归的方式，把所有的子cut，也从cuts中去掉，存入blockcuts
                    addCutToBlockCutList(data, children, level + 1, patternNo);
                }

                data.BlockCuts.Add(c);
                data.Cuts.Remove(c);
            }
        }
    }
}
